package com.mlming.springboot.service.impl;

import com.google.gson.Gson;
import com.lly835.bestpay.enums.BestPayTypeEnum;
import com.lly835.bestpay.enums.OrderStatusEnum;
import com.lly835.bestpay.model.PayRequest;
import com.lly835.bestpay.model.PayResponse;
import com.lly835.bestpay.service.BestPayService;
import com.mlming.springboot.dao.PayInfoMapper;
import com.mlming.springboot.enums.PayPlatformEnum;
import com.mlming.springboot.pojo.PayInfo;
import com.mlming.springboot.service.PayService;
import com.mlming.springboot.vo.PayInfoVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

@Service
public class PayServiceImpl implements PayService {
    @Autowired
    private PayInfoMapper payInfoMapper;
    @Autowired
    private BestPayService bestPayService; // 由BestPayConfig配置类的@Bean方法配置生成的支付类
    @Autowired
    private RabbitTemplate rabbitTemplate; // 用于生产者发送rabbitmq消息

    private final static String RABBITMQ_QUEUE_NAME = "payQueue";// 消息队列名称

    @Override
    public PayResponse createPay(Long orderNo, BigDecimal payAmount,BestPayTypeEnum type) {
        // 将订单信息写入数据库
        payInfoMapper.insertSelective(new PayInfo(orderNo,payAmount, PayPlatformEnum.getPayPlatformEnum(type).getCode()));
        // 创建本次支付请求类对象,传入支付类的pay方法发起支付
        PayRequest payRequest = new PayRequest();
        payRequest.setOrderName("支付订单号");
        payRequest.setPayTypeEnum(type);
        payRequest.setOrderAmount(payAmount.doubleValue());
        payRequest.setOrderId(String.valueOf(orderNo));
        PayResponse response = bestPayService.pay(payRequest);

        return response;
    }

    @Override
    public String asynNotifyCheck(String notifyData) {
        // 1. 签名验证: 直接调用sdk提供的方法进行验证:
        // 如果签名验证错误,会直接抛出异常;如果验证无误,结果会返回一个经过把返回的String封装后的对象以供我们更好地获取异步通知的数据
        // PayResponse(prePayParams=null, payUri=null, appId=null, timeStamp=null, nonceStr=null, packAge=null, signType=null, paySign=null, orderAmount=1.0, orderId=123456, outTradeNo=2021101522001430600501566851, mwebUrl=null, body=null, codeUrl=null, attach=null, payPlatformEnum=ALIPAY)
        PayResponse notifyResponse = bestPayService.asyncNotify(notifyData);
        // 2. 金额验证: 从数据库取出之前存进去的支付信息,对金额进行验证
        PayInfo payInfo = payInfoMapper.selectByOrderNo(Long.parseLong(notifyResponse.getOrderId()));
        if(payInfo == null) {
            throw new RuntimeException("数据库无该支付数据");
        }
        if(!(payInfo.getPayAmount().compareTo(BigDecimal.valueOf(notifyResponse.getOrderAmount())) == 0)) {
            // 如果金额验证不匹配:
            throw new RuntimeException("数据库中的支付金额与异步通知的金额不匹配");
        }
        // 如果 签名验证与金额验证都通过了,则:
        // 3. 修改数据库中该支付信息的支付状态 以及 支付流水号
        payInfo.setPlatformStatus(OrderStatusEnum.SUCCESS.name());
        payInfo.setPlatformNumber(notifyResponse.getOutTradeNo());
        payInfoMapper.updateByPrimaryKeySelective(payInfo);

        // 4. 通过rabbitmq异步通知申请支付的系统, 把部分支付数据发送回去
        PayInfoVo payInfoVo = new PayInfoVo();
        BeanUtils.copyProperties(payInfo,payInfoVo);
        rabbitTemplate.convertAndSend(RABBITMQ_QUEUE_NAME,new Gson().toJson(payInfoVo));

        // 5. 返回支付宝 通知成功的对应的"success"字符串
        return "success";
    }

}
